package com.hwpt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hwpt.config.MinIOConfig;
import com.hwpt.dto.admin.BatchDeleteFeedBackDTO;
import com.hwpt.dto.admin.FeedbackListDTO;
import com.hwpt.dto.user.FeedbackDTO;
import com.hwpt.entity.UserBasicInfo;
import com.hwpt.entity.UserFeedback;
import com.hwpt.entity.ImageResource;
import com.hwpt.exception.FeedBackException;
import com.hwpt.mapper.UserFeedbackMapper;
import com.hwpt.mapper.ImageResourceMapper;
import com.hwpt.result.PageResult;
import com.hwpt.service.FeedBackService;
import com.hwpt.service.UserInfoService;
import com.hwpt.utils.ImageMetaData;
import com.hwpt.utils.ImageUrlGenerator;

import com.hwpt.vo.admin.FeedBackDetailVO;
import com.hwpt.vo.admin.ListFeedbackVO;
import com.hwpt.vo.user.UserAllInfoVO;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.http.Method;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.hwpt.constant.ExceptionMessageConstant.*;

@Service
@RequiredArgsConstructor
@Slf4j
public class FeedBackServiceImpl implements FeedBackService {

    private final UserInfoService userInfoService;
    private final UserFeedbackMapper userFeedbackMapper;
    private final ImageResourceMapper imageResourceMapper; // 新增图片资源Mapper
    private final UserFeedbackMapper feedbackMapper;
    private final MinioClient minioClient;
    private final MinIOConfig minIOConfig;


    @Override
    @Transactional
    public List<String> saveFeedBack(FeedbackDTO feedbackDTO) {
        if (feedbackDTO == null) {
            throw new FeedBackException(FEEDBACK_EMPTY);
        }

        String hanWangId = feedbackDTO.getHanWangId();
        UserBasicInfo userBasicInfo = userInfoService.getUserByHanWangId(hanWangId);
        if (userBasicInfo == null) {
            throw new FeedBackException(USER_ID_NOT_FOUND);
        }


        // 先保存用户反馈信息到数据库，获取反馈ID
        Long feedbackId = saveUserFeedback(feedbackDTO, hanWangId);

        // 处理图片信息并生成URL，同时保存到图片表
        return processAndSaveFeedbackImages(feedbackDTO.getImages(), feedbackId);
    }


    /**
     * 处理反馈图片、生成URL并保存到图片表
     */
    private List<String> processAndSaveFeedbackImages(List<ImageMetaData> originalImages, Long feedbackId) {
        if (originalImages == null || originalImages.isEmpty()) {
            return new ArrayList<>();
        }

        List<String> imageUrls = new ArrayList<>();
        List<ImageResource> imageResources = new ArrayList<>();

        for (ImageMetaData originalImage : originalImages) {
            ImageMetaData processedImage = createImageMetaDataCopy(originalImage);
            String imageUrl = ImageUrlGenerator.generateImageUrl(processedImage);

            imageUrls.add(imageUrl);

            // 创建图片资源实体
            ImageResource imageResource = createImageResource(imageUrl, feedbackId);
            imageResources.add(imageResource);
        }

        // 批量保存图片资源到数据库
        saveImageResources(imageResources);

        return imageUrls;
    }

    /**
     * 创建图片元数据副本
     */
    private ImageMetaData createImageMetaDataCopy(ImageMetaData source) {
        ImageMetaData copy = new ImageMetaData();
        copy.setFileName(source.getFileName());
        copy.setFileSize(source.getFileSize());
        copy.setFileMd5(source.getFileMd5());
        copy.setMimeType(source.getMimeType());
        return copy;
    }

    /**
     * 创建图片资源实体
     */
    private ImageResource createImageResource(String imageUrl, Long feedbackId) {
        ImageResource imageResource = new ImageResource();
        imageResource.setFeedbackImageUrl(imageUrl);
        imageResource.setFeedbackId(feedbackId);
        imageResource.setCreateTime(LocalDateTime.now());
        return imageResource;
    }

    /**
     * 保存图片资源到数据库
     */
    private void saveImageResources(List<ImageResource> imageResources) {
        for (ImageResource imageResource : imageResources) {
            imageResource.setCreateTime(LocalDateTime.now());
            imageResourceMapper.insert(imageResource);
        }
        log.info("成功保存 {} 张图片资源到数据库", imageResources.size());
    }

    /**
     * 保存用户反馈信息到数据库并返回反馈ID
     */
    private Long saveUserFeedback(FeedbackDTO feedbackDTO, String hanWangId) {
        UserFeedback userFeedback = UserFeedback.builder()
                .hanWangId(hanWangId)
                .problemType(feedbackDTO.getType())
                .problemDesc(feedbackDTO.getDescription())
                .contactTel(feedbackDTO.getPhone())
                .feedbackStatus(0)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();

        userFeedbackMapper.insert(userFeedback);

        // 返回插入后生成的主键ID（需要确保UserFeedback实体有@TableId配置）
        return userFeedback.getFeedbackId();
    }

    // 反馈列表
    @Override
    public PageResult<ListFeedbackVO> feedbackList(FeedbackListDTO dto) {
        // 构建查询条件
        LambdaQueryWrapper<UserFeedback> queryWrapper = new LambdaQueryWrapper<>();

        // 根据反馈状态查询 - 修复 NPE 问题
        if (dto.getFeedbackStatus() != null && dto.getFeedbackStatus() > 0) {
            queryWrapper.eq(UserFeedback::getFeedbackStatus, dto.getFeedbackStatus());
        }

        // 根据问题类型查询
        if (StringUtils.isNotBlank(dto.getProblemType())) {
            queryWrapper.eq(UserFeedback::getProblemType, dto.getProblemType());
        }

        // 根据时间范围查询
        if (dto.getStartDate() != null && dto.getEndDate() != null) {
            queryWrapper.between(UserFeedback::getCreateTime, dto.getStartDate(), dto.getEndDate());
        } else if (dto.getStartDate() != null) {
            queryWrapper.ge(UserFeedback::getCreateTime, dto.getStartDate());
        } else if (dto.getEndDate() != null) {
            queryWrapper.le(UserFeedback::getCreateTime, dto.getEndDate());
        }

        // 根据搜索类型和关键词查询
        if (StringUtils.isNotBlank(dto.getSearchType()) && StringUtils.isNotBlank(dto.getKeyword())) {
            switch (dto.getSearchType()) {
                case "hanWangId":
                    queryWrapper.like(UserFeedback::getHanWangId, dto.getKeyword());
                    break;
                case "problemDesc":
                    queryWrapper.like(UserFeedback::getProblemDesc, dto.getKeyword());
                    break;
                case "contactTel":
                    queryWrapper.like(UserFeedback::getContactTel, dto.getKeyword());
                    break;
                default:
                    // 默认搜索所有字段
                    queryWrapper.and(wrapper -> wrapper
                            .like(UserFeedback::getHanWangId, dto.getKeyword())
                            .or()
                            .like(UserFeedback::getProblemDesc, dto.getKeyword())
                            .or()
                            .like(UserFeedback::getContactTel, dto.getKeyword()));
                    break;
            }
        }

        // 按创建时间倒序排列
        queryWrapper.orderByDesc(UserFeedback::getCreateTime);

        // 构建分页对象
        Page<UserFeedback> page = new Page<>(dto.getPage() != null ? dto.getPage() : 1,
                dto.getPageSize() != null ? dto.getPageSize() : 10);

        // 执行分页查询
        Page<UserFeedback> feedbackPage = feedbackMapper.selectPage(page, queryWrapper);

        // 转换为VO列表
        List<ListFeedbackVO> voList = feedbackPage.getRecords().stream()
                .map(feedback -> ListFeedbackVO.builder()
                        .feedbackId(feedback.getFeedbackId())
                        .hanWangId(feedback.getHanWangId())
                        .problemType(feedback.getProblemType())
                        .problemDesc(feedback.getProblemDesc())
                        .contactTel(feedback.getContactTel())
                        .feedbackStatus(feedback.getFeedbackStatus())
                        .createTime(feedback.getCreateTime())
                        .build())
                .collect(Collectors.toList());

        // 构建分页结果
        PageResult<ListFeedbackVO> result = new PageResult<>();
        result.setList(voList);
        result.setTotal(feedbackPage.getTotal());
        result.setPage(Math.toIntExact(feedbackPage.getCurrent()));
        result.setPageSize(Math.toIntExact(feedbackPage.getSize()));
        result.setTotalPages(Math.toIntExact(feedbackPage.getPages()));

        return result;
    }

    // 反馈详情
    @Override
    public FeedBackDetailVO feedbackDetail(Long feedbackId) {
        UserFeedback userFeedback = feedbackMapper.selectById(feedbackId);
        if (userFeedback == null) {
            throw new FeedBackException(FEEDBACK_NOT_EXIST);
        }

        FeedBackDetailVO feedBackDetailVO = new FeedBackDetailVO();
        UserAllInfoVO userAllInfoVO = userInfoService.getUserAllInfo(userFeedback.getHanWangId());
        BeanUtils.copyProperties(userFeedback, feedBackDetailVO);
        BeanUtils.copyProperties(userAllInfoVO, feedBackDetailVO);


        // 关联查询图片资源
        List<ImageResource> imageResources = imageResourceMapper.selectList(
                new LambdaQueryWrapper<ImageResource>()
                        .eq(ImageResource::getFeedbackId, feedbackId));

        // 转换为预签名URL列表
        List<String> presignedImageUrls = new ArrayList<>();

        for (ImageResource imageResource : imageResources) {
            String originalUrl = imageResource.getFeedbackImageUrl();
            try {
                String objectKey = extractObjectKey(originalUrl);
                // 生成预签名URL（有效期最多7天）
                String presignedUrl = minioClient.getPresignedObjectUrl(
                        GetPresignedObjectUrlArgs.builder()
                                .bucket(minIOConfig.getBucketName())
                                .object(objectKey)
                                .method(Method.GET)
                                .expiry(7, TimeUnit.DAYS)  // 注意：最大7天
                                .build());
                presignedImageUrls.add(presignedUrl);
            } catch (Exception e) {
                log.error("生成预签名URL失败，对象路径: {}", originalUrl, e);
                // 根据业务需求决定是否添加原始URL或跳过
                // presignedImageUrls.add(originalUrl); // 如果需要保留原始URL
                throw new FeedBackException(FEEDBACK_IMAGE_URL_ERROR);
            }
        }

        feedBackDetailVO.setFeedbackImage(presignedImageUrls);
        return feedBackDetailVO;
    }

    @Override
    public void updateFeedbackStatus(Long feedbackId) {
        if (feedbackId == null) {
            throw new FeedBackException(FEEDBACK_NOT_EXIST);
        }
        int newStatus = 1;
        LambdaUpdateWrapper<UserFeedback> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(UserFeedback::getFeedbackStatus, newStatus) // 指定要更新的字段和值
                .eq(UserFeedback::getFeedbackId, feedbackId); // 指定更新条件
        feedbackMapper.update(null, updateWrapper);
    }

    @Override
    public void deleteFeedback(Long feedbackId) {
        if (feedbackId == null) {
            throw new FeedBackException(FEEDBACK_NOT_EXIST);
        }
        feedbackMapper.deleteById(feedbackId);
    }

    @Override
    public void batchDeleteFeedback(BatchDeleteFeedBackDTO batchDeleteFeedBackDTO) {
        feedbackMapper.deleteByIds(batchDeleteFeedBackDTO.getFeedbackIds());
    }

    /**
     * 从完整的MinIO URL中提取对象键
     */
    private String extractObjectKey(String fullUrl) {
        try {
            URI uri = new URI(fullUrl);
            String path = uri.getPath();
            return path.startsWith("/") ? path.substring(1) : path;
        } catch (URISyntaxException e) {
            log.warn("无法解析URL: {}, 使用原值作为对象键", fullUrl, e);
            throw new FeedBackException(FEEDBACK_IMAGE_URL_ERROR);
        }
    }
}
